﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using InterfaceXAML.ExaPlanningService;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.Networking.BackgroundTransfer;
using Windows.Storage;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Xaml.Navigation;

// Pour en savoir plus sur le modèle d'élément Contrôle utilisateur, consultez la page http://go.microsoft.com/fwlink/?LinkId=234236

namespace InterfaceXAML.UserControls
{
    public sealed partial class MyImage : UserControl
    {
        // Prévenir des accès concurrent sur un même fichier
        private static readonly SemaphoreSlim _semaphore = new SemaphoreSlim(initialCount: 1);

        public Object Source {
            get { return GetValue(SourceProperty);}
            set { SetValue(SourceProperty,value);}
        }

        public BitmapImage SourceWithoutCaching
        {
            get { return imageSource.Source as BitmapImage; }
            set { 
                    imageSource.Source = value;
                    progressRing.IsActive = false;
                }
        }

        public static readonly DependencyProperty SourceProperty =
            DependencyProperty.Register(
                "Source",
                typeof(Object),
                typeof(MyImage),
                new PropertyMetadata(null, OnSourceChanged));

        public MyImage()
        {
            this.InitializeComponent();
            AttachHandler();
        }



        /// <summary>
        /// Gets the Source property. This dependency property 
        /// indicates the Image.Source that supports property change handling.
        /// </summary>
        public static object GetSource(DependencyObject d)
        {
            return d.GetValue(SourceProperty);
        }

        /// <summary>
        /// Sets the Source property. This dependency property 
        /// indicates the Image.Source that supports property change handling.
        /// </summary>
        public static void SetSource(DependencyObject d, object value)
        {
            d.SetValue(SourceProperty, value);
        }


        public void AttachHandler()
        {
            this.imageSource.ImageOpened += imageSource_ImageOpened;
            this.imageSource.ImageFailed += imageSource_ImageFailed;
        }
        public void DetachHandler()
        {
            this.imageSource.ImageOpened -= imageSource_ImageOpened;
            this.imageSource.ImageFailed -= imageSource_ImageFailed;
        }
        void imageSource_ImageFailed(object sender, ExceptionRoutedEventArgs e)
        {
            progressRing.IsActive = false;
        }

        void imageSource_ImageOpened(object sender, RoutedEventArgs e)
        {
            progressRing.IsActive = false;
            OpacityTransition.Begin();
            DetachHandler();
        }

        private static async void OnSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var imageInfo = e.NewValue as ImageInfoViewModel;
            var currentControl = d as MyImage;
            currentControl.imageSource.Source = await LoadPictureAsync(imageInfo);
        }

        private static async Task<BitmapImage> LoadPictureAsync(ImageInfoViewModel imageInfo)
        {
            var uri = imageInfo.URLImage;
            var fileName = uri.Split('/').LastOrDefault();
            
            var folderApp = ApplicationData.Current.LocalFolder;

            if (! (await IsLocalFolderExistAsync(folderApp, "Images")))
                await folderApp.CreateFolderAsync("Images");

            var folderImage = await folderApp.GetFolderAsync("Images");
            if (!await IsLocalFileExistAsync(folderImage, fileName))
            {
                await SavePictureAsync(uri);
            }
            else
            {
                var file = await folderImage.GetFileAsync(fileName);
                var properties = await file.Properties.GetImagePropertiesAsync();
                if(properties.DateTaken < imageInfo.LastModification)
                    await SavePictureAsync(uri);
            }

            return await GetPictureAsync(folderImage,fileName);
        }

        const int MAX_BUFFER_SIZE = 10 * 1024 * 1024;

        private static async Task SavePictureAsync(string urlPicture)
        {
            // Lock sémaphore
            await _semaphore.WaitAsync();
            try
            {
                Byte[] buffer = null;
                var client = new HttpClient();
                client.MaxResponseContentBufferSize = MAX_BUFFER_SIZE;
                buffer = await client.GetByteArrayAsync(new Uri(urlPicture));
                var folderApp = ApplicationData.Current.LocalFolder;
                
                var folderPicture = await folderApp.GetFolderAsync("Images");
                var file = await folderPicture.CreateFileAsync(urlPicture.Split('/').Last(), CreationCollisionOption.ReplaceExisting);
                await FileIO.WriteBytesAsync(file, buffer);
                // changer les properties de l'image pour la dateTaken
            }
            catch (Exception e)
            {

            }
            finally
            {
                // Libére le prochain thread
                _semaphore.Release();
            }
        }

        /// <summary>
        /// Récupère l'image en local dans le répértoire de l'application
        /// </summary>
        /// <param name="localFolder"></param>
        /// <param name="localcachefile"></param>
        /// <returns></returns>
        private static async Task<BitmapImage> GetPictureAsync(StorageFolder localFolder, String localcachefile)
        {
            var file = await localFolder.GetFileAsync(localcachefile);
            var stream = await file.OpenReadAsync();
            var bmp = new BitmapImage();
            bmp.SetSource(stream);
            return bmp;
        }

        /// <summary>
        /// Vérifie si un dossier existe
        /// </summary>
        /// <param name="localFolder"></param>
        /// <param name="localcachefolder"></param>
        /// <returns></returns>
        private static async Task<Boolean> IsLocalFolderExistAsync(StorageFolder localFolder, String localcachefolder)
        {
            try
            {
                await localFolder.GetFolderAsync(localcachefolder);
                return true;
            }
            catch (System.IO.FileNotFoundException)
            {
                return false;
            }
        }


        /// <summary>
        /// Vérifie si un fichier existe
        /// </summary>
        /// <param name="localFolder"></param>
        /// <param name="localcachefile"></param>
        /// <returns></returns>
        private static async Task<Boolean> IsLocalFileExistAsync(StorageFolder localFolder, String localcachefile)
        {
            try
            {
                await localFolder.GetFileAsync(localcachefile);
                return true;
            }
            catch (System.IO.FileNotFoundException)
            {
                return false;
            }
        }
    }
}
